// Regular expression class
// Copyright 2004 (C) Ralph Thomas

#ifndef REGEXP_H
#define REGEXP_H

#include <util/string.h>

namespace util {
	//
	/// The regexp class can use a PERL-style regexp to interpret a
	/// string. When a matching string is encountered, the regexp can
	/// execute various side-effects using any regexp::stringProcessor
	/// it has adopted.
	//
	class regexp {
	  public:
		//
		// class matchedString
		//
		/// The matchedString class is used to represent a string which
		/// matched this regexp.
		//
		class matchedString {
		  public:
			//
			// util::string getMatchedItem( unsigned int number )
			//
			/// Return the specified numbered matched item. Item
			/// zero is always the complete matched string, item
			/// one is the first variable part of the string which
			/// matched, for example:
			///
			///     re> /^abc(\\d+)as(\\d+)/
			///   data> abc1234def567
			///	0: abc1234def567
			///	1: 1234
			///	2: 567
			///
			/// \param	number	the index number of the item
			///			to be returned.
			/// \return	a string of the matched item, or the
			///		empty string if there was no item with
			///		that index.
			//
			virtual util::string getMatchedItem( unsigned int number ) const = 0;
		};

		//
		// class stringProcessor
		//
		/// The stringProcessor class runs the side-effects for a
		/// matched string. It is implemented by the user of the
		/// regexp class and is able to use the matchedString interface
		/// to figure out what side-effects to run.
		///
		/// The regexp class adopts a stringProcessor instance via the
		/// regexp::adoptStringProcessor method.
		//
		class stringProcessor {
		  public:
			//
			// virtual ~stringProcessor()
			//
			/// As the regexp adopts stringProcessor instances, it
			/// needs to know how to delete them.
			//
			virtual ~stringProcessor();

			//
			// void processString( const matchedString* str )
			//
			/// This method gets invoked when the regexp object
			/// that owns this stringProcessor instance matched
			/// a string. This stringProcessor instance should
			/// examine the matched string, if required, and then
			/// run whatever side-effects need to be run on it.
			///
			/// By default this function does nothing, making this
			/// stringProcessor pretty much null (having no side
			/// effects).
			///
			/// \param	str	a matchedString instance,
			///			representing the matched string
			///			which the regexp object
			///			encountered.
			//
			virtual void processString( const matchedString* str );
		};

		//
		// regexp* fromString( util::string expression )
		//
		/// Create a regexp object based on the given string. If the
		/// string is not a valid regular expression then NULL is
		/// returned.
		///
		/// \param	expression	the regular expression which
		///				this regexp object executes.
		/// \return	a new regexp object, or NULL.
		//
		static regexp* fromString( util::string expression );

		//
		// regexp* fromStringAndProcessor( util::string exp, class stringProcessor* processor )
		//
		/// Create a regexp object from the given string, and the
		/// stringProcessor instance. If the string is not a valid
		/// regular expression then NULL is returned AND THE STRING
		/// PROCESSOR IS DELETED!
		///
		/// \param	exp		the regular expression which
		///				the new regexp object executes
		/// \param	processor	the stringProcessor instance
		///				which runs the side-effects
		///				when the new regexp object
		///				encounters a string which it
		///				matches.
		/// \return	a new regexp object, or NULL.
		//
		static regexp* fromStringAndProcessor( util::string exp, stringProcessor* processor );

		//
		// ~regexp()
		//
		/// Release the memory for this regexp object, and all of it's
		/// adopted stringProcessors.
		//
		virtual ~regexp();

		//
		// bool match( util::string data )
		//
		/// Try to match the given string to the regexp. If false is
		/// returned, then there was no match. If true was returned
		/// then there was a match, and whichever processing actions
		/// were setup got executed.
		///
		/// \param	data	the string to try to match against
		/// \return	true if the string matched, and the side-
		///		-effects were run, false if the string did
		///		not match.
		//
		virtual bool match( util::string data ) = 0;

		//
		// void adoptStringProcessor( stringProcessor* sp )
		//
		/// Adopt the specifed string processor and add it to the
		/// list of stringProcessors to iterate through when a matching
		/// string is encountered.
		///
		/// \param	sp	the stringProcessor instance to adopt
		//
		virtual void adoptStringProcessor( stringProcessor* sp ) = 0;

		//
		// void releaseStringProcessor( stringProcessor* sp )
		//
		/// Release ownership of the stringProcessor object specified,
		/// and stop using it to process strings.
		/// The ownership of the reference returns to the caller, and
		/// the caller must delete it. If this regexp isn't using the
		/// specified stringProcessor then nothing happens.
		///
		/// \param	sp	the stringProcessor to release
		//
		virtual void releaseStringProcessor( stringProcessor* sp ) = 0;
	};
};

#endif

